package network;


import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.ProcessBuilder.Redirect;
import java.math.BigInteger;
import java.util.ArrayList;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;

import network.messages.KrakenClientMsg;
import network.messages.KrakenServerMsg;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Restrictions;
import bdd.sql.server.hibernate.HibernateUtil;
import bdd.sql.server.bean.Camera;
import bdd.sql.server.bean.Keystore;
import bdd.sql.server.bean.ServerSite;
import bdd.sql.server.bean.ServerStorage;
import bdd.sql.server.bean.Video;

import security.aes.AES256;
import security.authentification.Token;
import security.diffie.hellmann.CipherModule;
import security.diffie.hellmann.DiffieHellman;
import tools.AppletConstant;
import tools.ConfParser;
import tools.ExecuteExternalApplication;
import tools.FileUtils;
import tools.KeyParser;
import tools.StringUtils;
import tools.math.Math_;

/**
 * Traite les commandes reçues par le serveur.
 * @author Guillaume Poças & Jean-François Augé
 */
public class KrakenCommandInterpreter {
	
	private KrakenThread krakenThread;
	private String savedMessage;
	
	private DiffieHellman dh;
	
	/**
	 * Constructeur.
	 * @param thread
	 */
	public KrakenCommandInterpreter(KrakenThread thread){
		this.krakenThread = thread;
		this.savedMessage = "";
	}
	
	/**
	 * Interprete la commande.
	 * @param msg
	 */
	public void interpret(String msg){
		String[] msgCmd;
		@SuppressWarnings("unused")
		String[] testSavedMessage;
		
		System.out.println("KrakenCommandInterpreter: J'analyse : \""+msg+"\"");
		
		msgCmd = msg.split("  ");
		
		//Identification Client-Serveur
		if(msgCmd[0].equalsIgnoreCase(KrakenClientMsg.KRAKEN_CLIENT.toString())){
			krakenThread.sendCommand(KrakenServerMsg.KRAKEN_SERVER.makeCommand());
		}
		
		//nettoyage de répertoire
		else if(msgCmd[0].equalsIgnoreCase(KrakenClientMsg.CLEAN_FOLDER.toString())){
			if(msgCmd.length == 2){
				FileUtils.cleanDirectory(msgCmd[1]);
				krakenThread.sendCommand(KrakenServerMsg.FOLDER_CLEAN.makeCommand());
			}
		}
		
		//création répertoire
		else if(msgCmd[0].equalsIgnoreCase(KrakenClientMsg.CREATE_DIRECTORY.toString())){
			if(msgCmd.length == 2){
				if(!new File(msgCmd[1]).exists())
		            new File(msgCmd[1]).mkdirs();
				krakenThread.sendCommand(KrakenServerMsg.DIRECTORY_SAVED.makeCommand());
			}
		}
				
		//copie de fichier
		else if(msgCmd[0].equalsIgnoreCase(KrakenClientMsg.COPY_FILE.toString())){
			if(msgCmd.length == 4){
				this.savedMessage = msgCmd[0];
				krakenThread.sendCommand(KrakenServerMsg.WAITING_FILE.makeCommand(" "+msgCmd[1]," "+msgCmd[2]));
				FileUtils.tcpWaitingFileByWeight(krakenThread.getSocket(),msgCmd[2],Long.valueOf(msgCmd[3]));
				krakenThread.sendCommand(KrakenServerMsg.END_WAITING_FILE.makeCommand());
			}
			else if(msgCmd.length == 3){
				this.savedMessage = msgCmd[0];
				krakenThread.sendCommand(KrakenServerMsg.WAITING_FILE.makeCommand(" "+msgCmd[1]," "+msgCmd[2]));
				FileUtils.tcpWaitingFile(krakenThread.getSocket(),msgCmd[2]);
				krakenThread.sendCommand(KrakenServerMsg.END_WAITING_FILE.makeCommand());
			}
		}
		
		//fichier envoyé
		else if(msgCmd[0].equalsIgnoreCase(KrakenClientMsg.FILE_SENDED.toString())){
			if(savedMessage.equalsIgnoreCase(KrakenClientMsg.COPY_FILE.toString())){
				this.savedMessage = "";
				krakenThread.sendCommand(KrakenServerMsg.FILE_SAVED.makeCommand());
			}
		}
		
		//nouvelle vidéo sauvegardée sur site
		else if(msgCmd[0].equalsIgnoreCase(KrakenClientMsg.NEW_VIDEO_REGISTERED.toString())){
			if(msgCmd.length == 3){
				//1 = chemin re_vidéo & 2 = nom vidéo 
				//créer un keystore, récupérer vidéo, la chiffrer, l'envoyer sur serveur stockage
				final char[] ksPassword = StringUtils.generateRandomString(16).toCharArray();
				final char[] keyPassword = StringUtils.generateRandomString(16).toCharArray();
				
				if(!msgCmd[1].endsWith(System.getProperty("file.separator")))
					msgCmd[1] += System.getProperty("file.separator");
				
				ConfParser parser = new ConfParser();
				try {
					parser.parse(new File(AppletConstant.LOCAL_CONF));
				} catch (IOException e) {
					e.printStackTrace();
				}
				
				String alias = parser.getValue("AES_ALIAS");
				String storage_ip = parser.getValue("STORAGE_IP");
				String apply_encryption = parser.getValue("APPLY_ENCRYPTION");
				
				byte[] iv = StringUtils.stringToBytes(StringUtils.generateRandomString(16));
				
				// Create new Keystore
				String newKeystoreName = msgCmd[2].substring(0,(msgCmd[2].length()-4))+".keystore";
			    String newKeystorePath = msgCmd[1]+newKeystoreName;
			    File keystoreFile = new File(newKeystorePath);
			    AES256.createAESKeyStore(newKeystorePath, ksPassword, keyPassword, alias);
			    byte[] keystoreContent = FileUtils.fileToByteArray(keystoreFile, Math_.safeLongToInt(keystoreFile.length()));
			    Keystore keystore = new Keystore(newKeystoreName, "", iv, ksPassword, keyPassword, alias, keystoreFile.length(), true, "", keystoreContent);
			    
			    String clearVideoPath = msgCmd[1]+msgCmd[2];
			    String encryptedVideoPath = "", encryptedVideoName = "";
			    int encrypt = 0;
			    
			    //chiffrement video
			    if(apply_encryption.equals("YES")){
			    	encryptedVideoPath = clearVideoPath+".encrypt";
			    	encryptedVideoName = msgCmd[2]+".encrypt";
			    	AES256.encryptInputFile(clearVideoPath, encryptedVideoPath, newKeystorePath, ksPassword, keyPassword, alias, iv);
			    	encrypt = 1;
			    }
			    else{
			    	encryptedVideoPath = clearVideoPath;
			    	encryptedVideoName = msgCmd[2];
			    	encrypt = 0;
			    }
    
			    //copier encryptFile+newKeystorePath sur serveur stockage, puis les supprimer + msgCmd[1] !
				String[] path_informations = msgCmd[2].split("_");
				String osSeparator = System.getProperty("file.separator");
				String vidPath = parser.getValue("VIDEOS_PATH");
				
				Session session = HibernateUtil.getSession();
				Camera camera = (Camera) session.createCriteria(Camera.class).
						add(Restrictions.like("cam_ip", path_informations[0].split("-")[1])).list().get(0);
				ServerStorage serverStorage = (ServerStorage) session.createCriteria(ServerStorage.class).
						add(Restrictions.like("storserv_ip", storage_ip)).list().get(0);
				session.close();
				
				String finalPath = vidPath
						+ path_informations[0] + osSeparator //camName-camIP
						+ path_informations[1].substring(0,4) + osSeparator //année
						+ path_informations[1].substring(4,6) + osSeparator //mois
						+ path_informations[1].substring(6,8) + osSeparator; //jour
				String finalPathVideo = finalPath + encryptedVideoName;
				/*String finalPathKeystore = "";
				
				if(encrypt == 1)	finalPathKeystore = finalPathVideo.substring(0,(finalPathVideo.length()-(".mp4.encrypt".length())))+".keystore";
				else	finalPathKeystore = finalPathVideo.substring(0,(finalPathVideo.length()-(".mp4".length())))+".keystore";
				*/
				String[] commandMkdir = new String[]{"bash","-c","ssh test@"+storage_ip+" \"mkdir -p "+finalPath+"\""};
				String[] commandScpVideo = new String[]{"bash","-c","scp "+encryptedVideoPath+" test@"+storage_ip+":"+finalPathVideo};
				//String[] commandScpKeystore = new String[]{"bash","-c","scp "+newKeystorePath+" test@"+storage_ip+":"+finalPathKeystore};
				boolean savedInBDD = false;
				long weight = new File(encryptedVideoPath).length();
								
				try{
					Process procMkdir = new ProcessBuilder(commandMkdir).redirectError(Redirect.INHERIT).redirectOutput(Redirect.INHERIT).start();
					procMkdir.waitFor();
					if(procMkdir.exitValue() != 0)	System.out.println("commandMkdir:"+procMkdir.exitValue()+"|");
					
					Process procScpVideo = new ProcessBuilder(commandScpVideo).redirectError(Redirect.INHERIT).redirectOutput(Redirect.INHERIT).start();
					procScpVideo.waitFor();
					if(procScpVideo.exitValue() != 0)	System.out.println("commandScpVideo:"+procScpVideo.exitValue()+"|");
					
					//Process procScpKeystore = new ProcessBuilder(commandScpKeystore).redirectError(Redirect.INHERIT).redirectOutput(Redirect.INHERIT).start();
					//procScpKeystore.waitFor();
					//if(procScpKeystore.exitValue() != 0)	System.out.println("commandScpVideo:"+procScpKeystore.exitValue()+"|");
					
					if(procScpVideo.exitValue() == 0 /*&& procScpKeystore.exitValue() == 0*/){
						savedInBDD = true;
						if(new File(newKeystorePath).delete() == false || new File(clearVideoPath).delete() == false  || new File(encryptedVideoPath).delete() == false)
							System.out.println("DeleteFailed");
					}
					else	System.out.println("FilesCopyFailed");
				}catch(IOException e){
					e.printStackTrace();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				
				//vérifier la présence des fichiers sur le serveur de stockage au bon endroit
				if(savedInBDD){
					//insérer en BDD
					//System.out.println("Sauver en BDD : Video + Keystore !!");
					String timeBegin = path_informations[2].split("-")[0].substring(0,2)
							+ ":" + path_informations[2].split("-")[0].substring(2,4)
							+ ":" + path_informations[2].split("-")[0].substring(4,6);
					String duration = path_informations[2].split("-")[1];
					duration = duration.substring(0,duration.length()-4);
					session = HibernateUtil.getSession();
					Transaction tx = session.beginTransaction();
					Video newVideo = new Video(encryptedVideoName, finalPathVideo, camera, 
							serverStorage, path_informations[1].substring(0,4),
							path_informations[1].substring(4,6),
							path_informations[1].substring(6,8),
							timeBegin, duration, weight, keystore);
					session.save(newVideo);
					keystore.setVideo(newVideo);
					session.save(keystore);
					tx.commit();
					session.close();
					System.out.println(encryptedVideoName+" insérée en base!");
				}
				
				//ne pas terminer le thread
				krakenThread.setRunOff();
			}
			else{
				//error
			}
		}
				
		//Initialisation du système de chiffrement modulaire
		else if(msgCmd[0].equalsIgnoreCase(KrakenClientMsg.ENCRYPTION_DISTRIBUTION.toString())){
			if(msgCmd.length == 3){				
				if(msgCmd[1].equalsIgnoreCase("GLOBAL")){
					//récupérer chemin où copier sur serv global dans fichier config
					ConfParser parser = new ConfParser();
					try {
						parser.parse(new File(AppletConstant.GLOBAL_CONF));
					} catch (IOException e) {
						e.printStackTrace();
					}
					
					String path = parser.getValue("PATH_ENCRYPTION_DISTRIBUTION");
					krakenThread.sendCommand(KrakenServerMsg.PATH_ENCRYPTION_DISTRIBUTION.makeCommand(" GLOBAL"," "+msgCmd[2]," "+path));
				}
				else if(msgCmd[1].equalsIgnoreCase("LOCAL")){
					//récupérer chemin où copier sur serv local dans fichier config
					ConfParser parser = new ConfParser();
					try {
						parser.parse(new File(AppletConstant.LOCAL_CONF));
					} catch (IOException e) {
						e.printStackTrace();
					}
					
					String path = parser.getValue("PATH_ENCRYPTION_DISTRIBUTION");
					krakenThread.sendCommand(KrakenServerMsg.PATH_ENCRYPTION_DISTRIBUTION.makeCommand(" LOCAL", " "+msgCmd[2], " "+path));
				}
			}
			else if(msgCmd.length == 4){
				if(msgCmd[1].equalsIgnoreCase("LOCAL")){
					//1 = LOCAL & 2 = ip local & 3 = chemin stockage des fichiers copiés sur le global
					//créer un client avec les messages reçus
					
					String answer = "";
					String ip = msgCmd[2];
					ArrayList<String> msg_to_send = new ArrayList<String>();
					msg_to_send.add(KrakenClientMsg.KRAKEN_CLIENT.toString());
					msg_to_send.add(KrakenClientMsg.ENCRYPTION_DISTRIBUTION.makeCommand(" LOCAL"," "+msgCmd[3]));
					msg_to_send.add(KrakenClientMsg.END_CLIENT.toString());
							
					KrakenClient krakenClient = new KrakenClient(msg_to_send,ip);
					krakenClient.connect();
					krakenClient.communicate();
							
					answer = krakenClient.getFinalAnswer();
					if(answer.equalsIgnoreCase("END_SERVER")){
						System.out.println("Distribution locale des classes réussie");
						krakenThread.sendCommand(KrakenServerMsg.END_ENCRYPTION_DISTRIBUTION.makeCommand());
					}
					else{
						System.out.println("Distribution locale des classes failed");
						krakenThread.sendCommand(KrakenServerMsg.ERROR.makeCommand( " "+KrakenServerMsg.END_ENCRYPTION_DISTRIBUTION.msg));
					}
				}
			}
		}
		
		//Paramétrage du système de chiffrement modulaire
		else if(msgCmd[0].equalsIgnoreCase(KrakenClientMsg.ENCRYPTION_PARAMETER.toString())){
			if(msgCmd.length == 4){
				//1 = nom fichier & 2 = ip global & 3 = ip local
				String answer = "";
				String ip = msgCmd[2];
				ArrayList<String> msg_to_send = new ArrayList<String>();
				msg_to_send.add(KrakenClientMsg.KRAKEN_CLIENT.toString());
				msg_to_send.add(KrakenClientMsg.ENCRYPTION_PARAMETER.makeCommand(" "+msgCmd[1]," "+msgCmd[3]));
				msg_to_send.add(KrakenClientMsg.END_CLIENT.toString());
						
				KrakenClient krakenClient = new KrakenClient(msg_to_send,ip);
				krakenClient.connect();
				krakenClient.communicate();
						
				answer = krakenClient.getFinalAnswer();
				if(answer.equalsIgnoreCase("END_SERVER")){
					System.out.println("Paramétrage local de "+msgCmd[1]+" réussi");
					krakenThread.sendCommand(KrakenServerMsg.END_ENCRYPTION_PARAMETER.makeCommand());
				}
				else{
					System.out.println("Paramétrage local de "+msgCmd[1]+" failed");
					krakenThread.sendCommand(KrakenServerMsg.ERROR.makeCommand( " "+KrakenServerMsg.END_ENCRYPTION_DISTRIBUTION.msg));
				}
				//krakenThread.sendCommand(KrakenServerMsg.END_ENCRYPTION_PARAMETER.makeCommand());
			}
			else if(msgCmd.length == 3){
				//1 = nom fichier & 2 = ip local
				String answer = "";
				String ip = msgCmd[2];
				ArrayList<String> msg_to_send = new ArrayList<String>();
				msg_to_send.add(KrakenClientMsg.KRAKEN_CLIENT.toString());
				msg_to_send.add(KrakenClientMsg.ENCRYPTION_PARAMETER.makeCommand(" "+msgCmd[1]));
				msg_to_send.add(KrakenClientMsg.END_CLIENT.toString());
						
				KrakenClient krakenClient = new KrakenClient(msg_to_send,ip);
				krakenClient.connect();
				krakenClient.communicate();
						
				answer = krakenClient.getFinalAnswer();
				if(answer.equalsIgnoreCase("END_SERVER")){
					System.out.println("Paramétrage local de "+msgCmd[1]+" réussi");
					krakenThread.sendCommand(KrakenServerMsg.END_ENCRYPTION_PARAMETER.makeCommand());
				}
				else{
					System.out.println("Paramétrage local de "+msgCmd[1]+" failed");
					krakenThread.sendCommand(KrakenServerMsg.ERROR.makeCommand( " "+KrakenServerMsg.END_ENCRYPTION_DISTRIBUTION.msg));
				}
				//krakenThread.sendCommand(KrakenServerMsg.END_ENCRYPTION_PARAMETER.makeCommand());
			}
			else if(msgCmd.length == 2){
				//1 = nom fichier
				//copier le fichier directement
				ConfParser parser = new ConfParser();
				try {
					parser.parse(new File(AppletConstant.LOCAL_CONF));
				} catch (IOException e) {
					e.printStackTrace();
				}
				
				String pathToCopy = parser.getValue("PATH_ENCRYPTION_PARAMETER");
				String pathOfClasses = parser.getValue("PATH_ENCRYPTION_DISTRIBUTION");
				File[] files = FileUtils.listFiles(pathOfClasses);
				String tmp[];
				System.out.println(pathOfClasses);
				
				for(File file : files){
					System.out.println(file.getName());
					tmp = file.getName().split("\\.");
					if(tmp[0].equalsIgnoreCase(msgCmd[1])){
						try {
							FileUtils.cleanDirectory(pathToCopy);
							FileUtils.copyFileBuffered(file.getAbsolutePath(), pathToCopy+file.getName(), 4);
							krakenThread.sendCommand(KrakenServerMsg.END_ENCRYPTION_PARAMETER.makeCommand());
						} catch (FileNotFoundException e) {
							e.printStackTrace();
						} catch (IOException e) {
							e.printStackTrace();
						}
					}
				}
				//krakenThread.sendCommand(KrakenServerMsg.PATH_ENCRYPTION_PARAMETER.makeCommand(" "+msgCmd[1]," "+pathOfClasses, " "+pathToCopy));
			}
		}
		
		//generation clé RSA
		else if(msgCmd[0].equalsIgnoreCase(KrakenClientMsg.GENERATE_RSA_KEY.toString())){
			//appeler le programme pour génerer clé RSA
			krakenThread.sendCommand(KrakenServerMsg.RSA_KEY_GENERATED.makeCommand());
		}
		
		//generation clé
		else if(msgCmd[0].equalsIgnoreCase(KrakenClientMsg.GENERATE_KEY.toString())){
			if(msgCmd.length == 5){
				//servWeb: 1 = algo & 2 = ip global & 3 = ip local & 4 = global name
				String answer = "";
				String ip = msgCmd[2];
				ArrayList<String> msg_to_send = new ArrayList<String>();
				msg_to_send.add(KrakenClientMsg.KRAKEN_CLIENT.toString());
				msg_to_send.add(KrakenClientMsg.GENERATE_KEY.makeCommand(" "+msgCmd[1], " "+msgCmd[3], " "+msgCmd[4]));
				msg_to_send.add(KrakenClientMsg.END_CLIENT.toString());
						
				KrakenClient krakenClient = new KrakenClient(msg_to_send,ip);
				krakenClient.connect();
				krakenClient.communicate();
						
				answer = krakenClient.getFinalAnswer();
				if(answer.equalsIgnoreCase(KrakenServerMsg.END_SERVER.toString())){
					System.out.println("Génération de clé "+msgCmd[1]+" réussi");
					krakenThread.sendCommand(KrakenServerMsg.KEY_GENERATED.makeCommand());
				}
				else{
					System.out.println("Génération de clé "+msgCmd[1]+" failed");
					krakenThread.sendCommand(KrakenServerMsg.ERROR.makeCommand( " "+KrakenServerMsg.END_ENCRYPTION_DISTRIBUTION.msg));
				}
			}
			else if(msgCmd.length == 4){
				//serv global: 1 = algo & 2 = ip local & 3 = global name
				String algo = msgCmd[1];
				String ip = msgCmd[2];
				int out = -10;
				String size;
				
				ConfParser parser = new ConfParser();
				try {
					parser.parse(new File(AppletConstant.GLOBAL_CONF));
				} catch (IOException e) {
					e.printStackTrace();
				}
				String keyPath = parser.getValue("ENCRYPTION_KEY");
				String path = keyPath+algo+".key";
				
				if(algo.equalsIgnoreCase("lfsr")){
					size = parser.getValue("LFSR_SIZE");
				}
				else	size = "64";
				
				FileUtils.cleanDirectory(keyPath);
				String[] args = {parser.getValue("CRYPTO_CIPHER"), "-k", algo, path, size}; 
				
				//prog externe
				try {
					ExecuteExternalApplication eea = new ExecuteExternalApplication();
					out = eea.execute(args);
				} catch (IOException e) {
					e.printStackTrace();
				}
				
				if(out == 0){
					String key = KeyParser.parseKey(algo, path);
					if(key == null){
						System.out.println("Mauvais format de clé");
						//TODO ERR
					}
					else{
						Session session = HibernateUtil.getSession();
						Transaction tx = session.beginTransaction();
						ServerSite site = (ServerSite) session.createCriteria(ServerSite.class).
								add(Restrictions.like("siteserv_ip", ip)).list().get(0);
						site.setSiteserv_key(key);
						session.save(site);
						tx.commit();
						session.close();
						
						//envoie au serv local
						try {
							String dh_key = CipherModule.readDHKey(parser.getValue("DH_KEY")+msgCmd[3]+".dh");
							if(!dh_key.equalsIgnoreCase("")){
								String encryptedKeyPath = keyPath+algo+".key_c";
								FileUtils.copyFileBufferedEncryptedDH(keyPath+algo+".key", encryptedKeyPath, 4, dh_key);
								
								//(le serv local dechiffre le fichier arrive)
								String answer = "";
								ArrayList<String> msg_to_send = new ArrayList<String>();
								msg_to_send.add(KrakenClientMsg.KRAKEN_CLIENT.makeCommand());
								msg_to_send.add(KrakenClientMsg.GENERATE_KEY.makeCommand(" "+encryptedKeyPath, " "+msgCmd[3]));
								msg_to_send.add(KrakenClientMsg.END_CLIENT.makeCommand());
								
								KrakenClient krakenClient = new KrakenClient(msg_to_send,ip);
								krakenClient.connect();
								krakenClient.communicate();
								
								//on supprime le fichier cle genere
								FileUtils.cleanDirectory(keyPath);
										
								answer = krakenClient.getFinalAnswer();
								if(answer.equalsIgnoreCase(KrakenServerMsg.END_SERVER.toString())){
									System.out.println("Génération de clé "+msgCmd[1]+" réussi");
									krakenThread.sendCommand(KrakenServerMsg.KEY_GENERATED.makeCommand());
								}
								else{
									System.out.println("Génération de clé "+msgCmd[1]+" failed");
									krakenThread.sendCommand(KrakenServerMsg.ERROR.makeCommand( " "+KrakenServerMsg.END_ENCRYPTION_DISTRIBUTION.msg));
								}
							}
							else	System.out.println("Erreur sur la clé DH");
						} catch (IOException e) {
							e.printStackTrace();
						}
					}
				}
				else{
					System.out.println("Génération de clé "+msgCmd[1]+" failed");
					krakenThread.sendCommand(KrakenServerMsg.ERROR.makeCommand( " "+KrakenServerMsg.END_ENCRYPTION_DISTRIBUTION.msg));
				}
			}
			else if(msgCmd.length == 3){
				//serv local
				//1 = chemin fichier cle chiffree sur serv global & 2 = global name
				
				ConfParser parser = new ConfParser();
				try {
					parser.parse(new File(AppletConstant.LOCAL_CONF));
				} catch (IOException e) {
					e.printStackTrace();
				}
				String dh_key;
				try {
					FileUtils.cleanDirectory(parser.getValue("ENCRYPTION_KEY"));
					dh_key = CipherModule.readDHKey(parser.getValue("DH_KEY")+msgCmd[2]+".dh");
					String newKeyFile = msgCmd[1].substring(0, msgCmd[1].length()-2);
					//attend la copie du fichier
					krakenThread.sendCommand(KrakenServerMsg.WAITING_FILE.makeCommand(" "+msgCmd[1], " "+msgCmd[1]));
					FileUtils.tcpWaitingFile(krakenThread.getSocket(),msgCmd[1]);
					
					//une fois le fichier copie, on le dechiffre et supprime le chiffre
					try {
						FileUtils.copyFileBufferedEncryptedDH(msgCmd[1], newKeyFile, 4, dh_key);
						new File(msgCmd[1]).delete();
						this.savedMessage = KrakenClientMsg.COPY_FILE.makeCommand();
						
						//fin d'attente du client
						krakenThread.sendCommand(KrakenServerMsg.END_WAITING_FILE.makeCommand());
					} catch (FileNotFoundException e) {
						e.printStackTrace();
					} catch (IOException e) {
						e.printStackTrace();
					}
					
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			}
		}
		
		//demande de création d'un jeton
		else if(msgCmd[0].equalsIgnoreCase(KrakenClientMsg.ASK_FOR_TOKEN.toString())){
			if(msgCmd.length == 7){
				//servWeb: 1 = ip central & 2 = ip flux & 3 = typeDemande
				//& 4 = id_video (user:id_videos) & 5 = ip site & 6 = ip cam
				String answer = "";
				ArrayList<String> msg_to_send = new ArrayList<String>();
				msg_to_send.add(KrakenClientMsg.KRAKEN_CLIENT.makeCommand());
				msg_to_send.add(KrakenClientMsg.ASK_FOR_TOKEN.makeCommand(" "+msgCmd[2], " "+msgCmd[3], " "+msgCmd[4], " "+msgCmd[5], " "+msgCmd[6]));
				msg_to_send.add(KrakenClientMsg.END_CLIENT.makeCommand());
				
				KrakenClient krakenClient = new KrakenClient(msg_to_send,msgCmd[1]);
				krakenClient.connect();
				krakenClient.communicate();
						
				answer = krakenClient.getFinalAnswer();
				if(answer.equalsIgnoreCase(KrakenServerMsg.END_SERVER.toString())){
					System.out.println("Génération de jeton "+msgCmd[1]+" réussie");
					krakenThread.sendCommand(KrakenServerMsg.SEND_GENERATED_AUTHENTIFICATION_TOKEN.makeCommand(" "+StringUtils.bytesToString(krakenClient.getSaved_data())));
				}
				else{
					System.out.println("Génération de jeton "+msgCmd[1]+" failed");
					krakenThread.sendCommand(KrakenServerMsg.ERROR.makeCommand( " "+KrakenServerMsg.SEND_GENERATED_AUTHENTIFICATION_TOKEN.msg));
				}
			}
			else if(msgCmd.length == 6){
				//servCentral: 1 = ip flux & 2 = typeDemande & 3 = id_video (user:id_videos) 
				//4 = ip site & 5 = ip cam
				String answer = "";
				ArrayList<String> msg_to_send = new ArrayList<String>();
				msg_to_send.add(KrakenClientMsg.KRAKEN_CLIENT.makeCommand());
				msg_to_send.add(KrakenClientMsg.ASK_FOR_TOKEN.makeCommand(" "+msgCmd[2], " "+msgCmd[3], " "+msgCmd[4], " "+msgCmd[5]));
				msg_to_send.add(KrakenClientMsg.END_CLIENT.makeCommand());
				
				KrakenClient krakenClient = new KrakenClient(msg_to_send,msgCmd[1]);
				krakenClient.connect();
				krakenClient.communicate();
						
				answer = krakenClient.getFinalAnswer();
				if(answer.equalsIgnoreCase(KrakenServerMsg.END_SERVER.toString())){
					krakenThread.sendCommand(KrakenServerMsg.SEND_GENERATED_AUTHENTIFICATION_TOKEN.makeCommand(" "+StringUtils.bytesToString(krakenClient.getSaved_data())));
				}
				else{
					System.out.println("Génération de jeton "+msgCmd[1]+" failed");
					krakenThread.sendCommand(KrakenServerMsg.ERROR.makeCommand( " "+KrakenServerMsg.SEND_GENERATED_AUTHENTIFICATION_TOKEN.msg));
				}
			}
			else if(msgCmd.length == 5){
				//servFlux: 1 = typeDemande & 2 = id_video (user:id_videos) 3 = ip site & 4 = ip cam
				//Token token = new Token("YES_TOKEN");
				Token token = null;
				
				//si c'est une demande de Streaming
				if(msgCmd[1].equals("0") && msgCmd[2].equals("0")){
					token = new Token(new Integer(msgCmd[1]), msgCmd[2], msgCmd[3], msgCmd[4]);
				}
				//si c'est une demande de Telechargement
				else if(msgCmd[1].equals("1") && !msgCmd[2].equals("0")){
					token = new Token(new Integer(msgCmd[1]), msgCmd[2], msgCmd[3], msgCmd[4]);
				}
				//si c'est une demande de clés
				else if(msgCmd[1].equals("2") && !msgCmd[2].equals("0")){
					token = new Token(new Integer(msgCmd[1]), msgCmd[2], msgCmd[3], msgCmd[4]);
				}
				else{
					//error
					krakenThread.sendCommand(KrakenServerMsg.ERROR.makeCommand(" "+KrakenClientMsg.ASK_FOR_TOKEN.toString()));
				}
				
				//TODO récupérer les mdp depuis la BDD ?
				final char[] ksPassword = {'t','o','t','o'};
				final char[] keyPassword = {'t','o','t','o'};
				
				ConfParser parser = new ConfParser();
				try {
					parser.parse(new File(AppletConstant.AUTH_CONF));
				} catch (IOException e) {
					e.printStackTrace();
				}
				
				String ksPath = parser.getValue("AES_KEYSTORE");
				String alias = parser.getValue("AES_ALIAS");
				//TODO charger l'IV depuis quelque part !
				byte[] iv = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
			    IvParameterSpec ivspec = new IvParameterSpec(iv);
				
				// Load Key From Keystore
				//System.out.println(ksPath+"&"+ksPassword.toString()+"&"+keyPassword.toString()+"&"+alias);
				SecretKey aesKey = AES256.loadKeyFromKeyStore(ksPath, ksPassword, keyPassword, alias);
				Cipher encryptCipher = AES256.initCipherEncrypt(aesKey, ivspec);
				byte[] encryptedData = AES256.encrypt(token.getInformation(),aesKey,encryptCipher);
				
				krakenThread.sendCommand(KrakenServerMsg.SEND_GENERATED_AUTHENTIFICATION_TOKEN.makeCommand( " "+StringUtils.bytesToString(encryptedData)));
			}
			else{
				krakenThread.sendCommand(KrakenServerMsg.ERROR.makeCommand(" "+KrakenClientMsg.ASK_FOR_TOKEN.toString()));
			}
		}
		
		
		//fin de la communication
		else if(msgCmd[0].equalsIgnoreCase(KrakenClientMsg.END_CLIENT.toString())){
			krakenThread.sendCommand(KrakenServerMsg.END_SERVER.makeCommand());
			krakenThread.setRunOff(); //obligatoire pour arrêter le thread
		}
		
		// protocole diffie-hellman
		else if(msgCmd[0].equalsIgnoreCase(KrakenClientMsg.DH_KEY.toString())) {
			// serveur web
			if(msgCmd.length == 4) {
				// créer un nouveau client pour propager une nouvelle clé dh
				ArrayList<String> msgToGlobal = new ArrayList<String>();
				msgToGlobal.add(KrakenClientMsg.KRAKEN_CLIENT.toString());
				msgToGlobal.add(KrakenClientMsg.DH_KEY.makeCommand(" "+msgCmd[2], " "+msgCmd[3]));
				msgToGlobal.add(KrakenClientMsg.END_CLIENT.toString());
				
				KrakenClient krakenClient = new KrakenClient(msgToGlobal, msgCmd[1]);
				krakenClient.connect();
				krakenClient.communicate();
				
				String answer = krakenClient.getFinalAnswer();
				
				if(answer.equalsIgnoreCase("END_SERVER")) {
					System.out.println("Transfert TCP réussi");
					krakenThread.sendCommand(KrakenServerMsg.DH_ACK.makeCommand());
				}
				else
					krakenThread.sendCommand(KrakenServerMsg.ERROR.makeCommand(" TCP_TRANSFERT_FAILED"));
			}
			// serveur global
			else if(msgCmd.length == 3) {
				// generer PGA
				if(dh == null) {
					System.out.println("génération de P et G");
					dh = new DiffieHellman(4, 1024);
					try {
						dh.gen_P();
						dh.gen_G();
					} catch (InterruptedException e) {
						e.printStackTrace();
						krakenThread.sendCommand(KrakenServerMsg.ERROR.makeCommand(" DH_COULD_NOT_CREATE_P_OR_G"));
					}
					System.out.println("P et G générés");
				}
				
				try {
					dh.gen_A();
				} catch (InterruptedException e) {
					e.printStackTrace();
					krakenThread.sendCommand(KrakenServerMsg.ERROR.makeCommand(" DH_COULD_NOT_CREATE_A"));
				}
				
				ArrayList<String> msgToLocal = new ArrayList<String>();
				msgToLocal.add(KrakenClientMsg.KRAKEN_CLIENT.makeCommand());
				msgToLocal.add(KrakenClientMsg.DH_KEY.makeCommand());
				msgToLocal.add(KrakenClientMsg.SEND_P.makeCommand(" "+dh.getP().toString()));
				msgToLocal.add(KrakenClientMsg.SEND_G.makeCommand(" "+dh.getG().toString()));
				msgToLocal.add(KrakenClientMsg.SEND_A.makeCommand(" "+dh.getA().toString(), " "+msgCmd[2]));
				msgToLocal.add(KrakenClientMsg.END_CLIENT.makeCommand());
				
				KrakenClient krakenClient = new KrakenClient(msgToLocal, msgCmd[1]);
				krakenClient.connect();
				krakenClient.communicate();
				
				String answer = krakenClient.getFinalAnswer();
				
				if(answer.equalsIgnoreCase("END_SERVER"))
					System.out.println("Transfert TCP réussi");
				else
					krakenThread.sendCommand(KrakenServerMsg.ERROR.makeCommand(" TCP_TRANSFERT_FAILED"));
				
				// récupérer B
				dh.setB(krakenClient.getB());
				
				// générer la clé
				System.out.println("clé serveur global "+dh.compute_key(dh.getB()));
				
				// réponse ajoutée
				krakenThread.sendCommand(KrakenServerMsg.DH_ACK.makeCommand());
				
				try {
					ConfParser conf = new ConfParser();
					conf.parse(new File(AppletConstant.GLOBAL_CONF));
					CipherModule.writeDHKey(conf.getValue("DH_KEY")+msgCmd[2]+".dh", dh.getK().toString());
				} catch (IOException e) {
					e.printStackTrace();
					krakenThread.sendCommand(KrakenServerMsg.ERROR.makeCommand(" CONF_CANT_OPEN_FILE"));
				}
			}
			
			// côté serveur local
			else if(msgCmd.length == 1) {
				dh = new DiffieHellman(4, 1024);
				krakenThread.sendCommand(KrakenServerMsg.DH_ACK.makeCommand());
			}
			
			// problème
			else
				krakenThread.sendCommand(KrakenServerMsg.UNKNOWN_COMMAND.makeCommand(msg));
		}
		
		// côté serveur local
		else if(msgCmd[0].equalsIgnoreCase(KrakenClientMsg.SEND_P.toString())) {
			// stocker P (synchroniser?)
			dh.setP(new BigInteger(msgCmd[1]));
			krakenThread.sendCommand(KrakenServerMsg.RECEIVED_P.makeCommand());
		}
		else if(msgCmd[0].equalsIgnoreCase(KrakenClientMsg.SEND_G.toString())) {
			// stocker G (synchroniser?)
			dh.setG(new BigInteger(msgCmd[1]));
			krakenThread.sendCommand(KrakenServerMsg.RECEIVED_G.makeCommand());
		}
		else if(msgCmd[0].equalsIgnoreCase(KrakenClientMsg.SEND_A.toString())) {
			if(msgCmd.length == 3) {
				// stocker A (synchroniser?)
				dh.setA(new BigInteger(msgCmd[1]));
				
				// générer B
				try {
					dh.gen_B();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
	
				krakenThread.sendCommand(KrakenServerMsg.SEND_B.makeCommand(" "+dh.getB().toString()));
				
				// générer la clé
				System.out.println("clé serveur local "+dh.compute_key(dh.getA()));
				try {
					ConfParser conf = new ConfParser();
					conf.parse(new File(AppletConstant.LOCAL_CONF));
					CipherModule.writeDHKey(conf.getValue("DH_KEY")+msgCmd[2]+".dh", dh.getK().toString());
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			else
				krakenThread.sendCommand(KrakenServerMsg.UNKNOWN_COMMAND.makeCommand(msg));
		}
		
		//Commande inconnue
		else
			krakenThread.sendCommand(KrakenServerMsg.UNKNOWN_COMMAND.makeCommand(msg));
			
	}
	
}
